﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _plants_vs_zombies
{
    /// <summary>
    /// 游戏类
    /// </summary>
    class Game
    {
        /// <summary>
        /// 游戏的矩阵长宽及游戏map大小
        /// </summary>
        private const int Cols = 9;
        private const int Rows = 5;
        private const int GameWidth = 1000;
        private const int GameHeight = 700;

        /// <summary>
        /// 僵尸的产生数目
        /// </summary>
        private int zombienumber = 0;

        /// <summary>
        /// 判断游戏胜利的变量
        /// </summary>
        public int k = 0;

        /// <summary>
        /// 关闭胜利messagebox和控制显示宇智波的变量
        /// </summary>
        public int l = 0;

        /// <summary>
        /// 游戏自带的timer
        /// </summary>
        private System.Timers.Timer Timer;

        /// <summary>
        /// 被攻击的僵尸组
        /// </summary>
        private List<Zombie> zombiesattacked { get; set; }

        /// <summary>
        /// 定义僵尸Y坐标
        /// </summary>
        private int ZombieY { get; set; }

        /// <summary>
        /// 定义僵尸横坐标
        /// </summary>
        public int ZombieX { get; set; }

        /// <summary>
        ///定义消耗值
        /// </summary>
        private int Consume { get; set; }

        /// <summary>
        /// 游戏太阳计数变量
        /// </summary>
        private int Money { get; set; }

        /// <summary>
        /// 定义块类集合
        /// </summary>
        private List<Block> blocks { get; set; }

        /// <summary>
        /// 定义僵尸组
        /// </summary>
        private List<Zombie> zombies { get; set; }

        /// <summary>
        /// 定义子弹组
        /// </summary>
        private List<Pea> peas { get; set; }

        /// <summary>
        /// 定义阳光组
        /// </summary>
        private List<Sun> suns { get; set; }

        /// <summary>
        /// 定义植物类型
        /// </summary>
        private List<Plant> plants { get; set; }

        /// <summary>
        /// Mouseblock的初始化
        /// </summary>
        private Plant Mouseblock { get; set; }

        /// <summary>
        /// 定义委托
        /// </summary>
        public delegate void Gamechanged();

        /// <summary>
        /// 定义游戏结束
        /// </summary>
        public delegate void Gameover();

        /// <summary>
        /// 定义游戏改变事件
        /// </summary>
        public event Gamechanged gameChanged;

        /// <summary>
        /// 定义游戏结束事件
        /// </summary>
        public event Gameover gameOver;

        /// <summary>
        /// 定义游戏结束框出现的时间
        /// </summary>
        public DateTime interval = System.DateTime.Now.AddDays(1);

        /// <summary>
        /// 下次产生阳光的时间
        /// </summary>
        private DateTime NextSunTime { get; set; }

        /// <summary>
        /// 下次产生僵尸的时间
        /// </summary>
        private DateTime NextZombieTime { get; set; }

        /// <summary>
        /// 初始化
        /// </summary>
        /// 
        public Game()
        {
            //初始化太阳数
            Money = 0;
            //初始化block
            blocks = new List<Block>();
            //初始化植物类
            plants = new List<Plant>();
            //定义blcoks的rectangle
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    Rectangle rectangle = new Rectangle(100 * j + 60, 88 + 116 * i, 80, 86);
                    Block block = new Block(rectangle);
                    blocks.Add(block);
                }
            }

            /*定义Mouseblock的rectangle，
            将植物卡片的rectangle和卡片属性加入到plants集合里面*/
            Rectangle rectangle1 = new Rectangle(220, 4, 90, 66);
            Rectangle rectangle2 = new Rectangle(350, 4, 90, 66);
            Rectangle rectangle3 = new Rectangle(850, 4, 90, 66);
            Rectangle rectangle4 = new Rectangle(480, 4, 90, 66);
            plants.Add(new Plant(rectangle1, BlockStatus.豌豆射手));
            plants.Add(new Plant(rectangle2, BlockStatus.向日葵));
            plants.Add(new Plant(rectangle3, BlockStatus.铲子));
            plants.Add(new Plant(rectangle4, BlockStatus.土豆));

            //初始化时钟
            Timer = new System.Timers.Timer();
            Timer.Elapsed += Timer_Elapsed;
            Timer.Start();
            //初始化zombies
            zombies = new List<Zombie>();
            //初始化peas
            peas = new List<Pea>();
            //初始化suns
            suns = new List<Sun>();
            //初始化产生阳光时间点
            NextSunTime = System.DateTime.Now;
            //初始化产生僵尸时间点
            NextZombieTime = System.DateTime.Now.AddSeconds(20);
            //初始化zombiesattacked
            zombiesattacked = new List<Zombie>();
        }

        /// <summary>
        /// game的时钟
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            //时钟处理程序
            Timer.Stop();
            //处理僵尸移动
            Zombie zombieout = null;
            foreach (var zombie in zombies)
            {
                zombie.Move();
                //初始化zombieX
                ZombieX = zombie.Rectangle.X;
                if (ZombieX <= -200)
                {
                    
                    k = 3;
                    break;
                }
                //如果僵尸出界
                if (ZombieX < -220)
                {
                    zombieout = zombie;
                }
            }
            //移除出界的僵尸
            zombies.Remove(zombieout);
            //处理子弹移动及回收
            Pea peaout = null;
            foreach (var pea in peas)
            {
                pea.Move();
                //如果pea出界
                if (pea.Rectangle.X > 900)
                {
                    //记下来
                    peaout = pea;
                    break;
                };
            }
            //移除出界的pea
            if (peaout != null)
                peas.Remove(peaout);

            //处理天上产生阳光及阳光的消失
            if (System.DateTime.Now > NextSunTime)
            {
                Random rnd = new Random();
                Rectangle recSun = new Rectangle(rnd.Next(100, 800), 0, 100, 100);
                //到点了产生新的阳光
                suns.Add(new Sun(recSun));
                NextSunTime = System.DateTime.Now.AddSeconds(5);
            }

            //处理随机每排产生僵尸
            if (System.DateTime.Now > NextZombieTime && zombienumber <= 10)
            {
                //随机获得zombieY的值
                Random rnd = new Random();
                int i = rnd.Next(0, 5);
                switch (i)
                {
                    case 0:
                        ZombieY = 80;
                        break;
                    case 1:
                        ZombieY = 200;
                        break;
                    case 2:
                        ZombieY = 320;
                        break;
                    case 3:
                        ZombieY = 440;
                        break;
                    case 4:
                        ZombieY = 560;
                        break;
                    default:
                        break;
                }
                Rectangle recZombie = new Rectangle(1000, ZombieY, 200, 100);
                //到点了产生新的僵尸
                zombies.Add(new Zombie(recZombie, 8));
                //计数
                zombienumber++;
                //每过12秒产生一个僵尸
                NextZombieTime = System.DateTime.Now.AddSeconds(12);
            }
            //产生最后一波僵尸
            if (zombienumber == 11)
            {
                Rectangle recZombie1 = new Rectangle(1300, 80, 200, 100);
                Rectangle recZombie2 = new Rectangle(1300, 200, 200, 100);
                Rectangle recZombie3 = new Rectangle(1300, 320, 200, 100);
                Rectangle recZombie4 = new Rectangle(1300, 440, 200, 100);
                Rectangle recZombie5 = new Rectangle(1300, 560, 200, 100);
                Rectangle recZombie6 = new Rectangle(1500, 80, 200, 100);
                Rectangle recZombie7 = new Rectangle(1500, 200, 200, 100);
                Rectangle recZombie8 = new Rectangle(1500, 320, 200, 100);
                Rectangle recZombie9 = new Rectangle(1500, 440, 200, 100);
                Rectangle recZombie10 = new Rectangle(1500, 560, 200, 100);
                zombies.Add(new Zombie(recZombie1, 8));
                zombies.Add(new Zombie(recZombie2, 8));
                zombies.Add(new Zombie(recZombie3, 8));
                zombies.Add(new Zombie(recZombie4, 8));
                zombies.Add(new Zombie(recZombie5, 8));
                zombies.Add(new Zombie(recZombie6, 8));
                zombies.Add(new Zombie(recZombie7, 8));
                zombies.Add(new Zombie(recZombie8, 8));
                zombies.Add(new Zombie(recZombie9, 8));
                zombies.Add(new Zombie(recZombie10, 8));
                zombienumber += 10;
            }
            //处理碰撞
            HandleTouch();
            //检查游戏里有没有僵尸存活
            if (zombienumber == 21 && zombies.Count == 0)
            {
                k = 2;
            }
            // 处理阳光移动和阳光存活
            Sun sunNow = null;
            foreach (var sun in suns)
            {
                //阳光移动
                if (sun.Rectangle.Y < 500)
                {
                    sun.Move();
                }
                //判断到点的阳光
                if (System.DateTime.Now > sun.DeadTime)
                {
                    //记下来
                    sunNow = sun;
                    break;
                };
            }
            //移除到点的阳光
            if (sunNow != null)
                suns.Remove(sunNow);
            //处理向日葵产生阳光
            foreach (var block in blocks.Where(m => m.Status == BlockStatus.向日葵 && System.DateTime.Now > m.NextGenerateTime))
            {
                //向日葵产生阳光
                Rectangle rec = new Rectangle(block.Rectangle.X, block.Rectangle.Y, 100, 100);
                //添加具有不可移动属性的阳光
                suns.Add(new Sun(rec, false));
                //向日葵每八秒产生一个阳光
                block.NextGenerateTime = System.DateTime.Now.AddSeconds(8);
            }
            //处理豌豆射手发射子弹
            foreach (var block in blocks.Where(m => m.Status == BlockStatus.豌豆射手 && System.DateTime.Now > m.NextGenerateTime))
            {
                //根据僵尸block的坐标产生子弹
                Rectangle rec = new Rectangle(block.Rectangle.X + 20, block.Rectangle.Y - 5, 80, 40);
                peas.Add(new Pea(rec));
                //豌豆射手每两秒发射一颗子弹
                block.NextGenerateTime = System.DateTime.Now.AddSeconds(2);
            }
            //处理碰撞
            HandleTouch();
            gameChanged?.Invoke();
            gameOver?.Invoke();
            k = 0;
            l = 0;
            Timer.Start();
        }

        /// <summary>
        /// 处理碰撞僵尸减血
        /// </summary>
        private void HandleTouch()
        {
            //初始化被触碰到的豌豆
            Pea peatouched = null;
            //初始化被打死的僵尸
            //Zombie zombiedead = null;
            //处理僵尸和豌豆的碰撞问题       
            for (int j = 0; j < zombies.Count; j++)
            {
                for (int k = 0; k < peas.Count; k++)
                {
                    if (zombies[j].Rectangle.IntersectsWith(peas[k].Rectangle))
                    {
                        //豌豆和僵尸撞上了
                        peatouched = peas[k];
                        //僵尸的血量减1
                        zombies[j].zombielifenow--;
                    }
                }
            }
            //移除撞上的pea
            if (peatouched != null)
            {
                peas.Remove(peatouched);
            } 
            //移除血量为0的僵尸
            zombies.RemoveAll(o => { return o.zombielifenow<=0; });
            //处理僵尸吃植物问题

            //初始化下一次僵尸攻击的时间使之进入if里面
            DateTime nextattacktime = System.DateTime.Now.AddHours(1);
            foreach (var block in blocks.Where(m => m.Plantlife > 0))
            {
                for (int i = 0; i < zombies.Count; i++)
                {
                    if (zombies[i].Rectangle.IntersectsWith(block.Rectangle))
                    {
                        //僵尸和植物撞上了
                        //僵尸进行攻击
                        if (nextattacktime > System.DateTime.Now && block.Plantlife >= 1)
                        {
                            block.Plantlife--;
                            //防止多个僵尸将块的血量攻击为负数
                            if (block.Plantlife < 0)
                            {
                                block.Plantlife = 0;
                            }
                            nextattacktime = System.DateTime.Now.AddSeconds(4);
                        }
                        //防止只有一个僵尸获得了速度
                        if (block.Plantlife >= 0 && block.Plantlife < 10)
                        {
                            //停下来
                            zombies[i].Isattack=false;
                        }
                        zombies[i].MoveBack();
                    }
                }
            }
            //将被僵尸吃掉的植物移除
            foreach (var block in blocks.Where(m => m.Plantlife <= 0))
            {
                block.Status = BlockStatus.空白;
            }
        }
        /// <summary>
        /// 绘制当前游戏的场景
        /// </summary
        /// <param name="g">绘图句柄</param>
        /// <param name="size">游戏区域尺寸</param>
        public void Draw(Graphics g, Size size)
        {
            /*画背景（二次绘画）
            定义空白的画*/
            Image img = new Bitmap(GameWidth, GameHeight);
            Graphics _g = Graphics.FromImage(img);
            //定义一个矩形，长度是预定义
            Rectangle rec = new Rectangle(0, 70, GameWidth, GameHeight - 70);
            _g.DrawImage(Properties.Resources.bg, rec);

            //画卡片及道具
            Rectangle rectangle1 = new Rectangle(50, 0, GameWidth - 70, 70);
            Rectangle rectangle2 = new Rectangle(GameWidth - 140, 10, 70, 50);
            Rectangle rectangle3 = new Rectangle(222, 5, 100, 61);
            Rectangle rectangle4 = new Rectangle(350, 5, 100, 61);
            _g.DrawImage(Properties.Resources.boarder, rectangle1);
            _g.DrawImage(Properties.Resources.铲子, rectangle2);
            Rectangle rectangle5 = new Rectangle(468, 5, 100, 61);
            Rectangle rectangle6 = new Rectangle(80, 80, 500, 100);
            //画阴影
            foreach (var block in blocks.Where(m => m.Status != BlockStatus.空白))
            {
                Rectangle recshadow = new Rectangle(block.Rectangle.X-25, block.Rectangle.Y+70, 130, 20);
                _g.DrawImage(Properties.Resources.阴影, recshadow);
            }
            //如果阳光数足够点亮土豆卡片
            if (Money >= 50)
            {
                _g.DrawImage(Properties.Resources.todou亮, rectangle5);
            }
            if (Money < 50)
            {
                _g.DrawImage(Properties.Resources.todou黑, rectangle5);
            }
            //如果阳光数足够点亮向日葵卡片
            if (Money >= 50)
            {
                _g.DrawImage(Properties.Resources.向日葵卡片2, rectangle4);
            }
            //如果阳光数足够点亮豌豆射手卡片
            if (Money >= 100)
            {
                _g.DrawImage(Properties.Resources.豌豆射手卡片2, rectangle3);
            }

            /*画数字
            Create font and brush.*/
            Font drawFont = new Font("Arial", 16);
            SolidBrush drawBrush = new SolidBrush(Color.Black);
            _g.DrawString(Money.ToString(), drawFont, drawBrush, 110, 50);

            //画格子
            foreach (var block in blocks)
            {
                block.Draw(_g);
            }

            //画mousemove的图片
            if (Mouseblock != null)
            {
                Mouseblock.Draw(_g);
            }
            //画僵尸
            for (int i = 0; i < zombies.Count; i++)
            {
                if (zombies[i] != null)
                    zombies[i].Draw(_g);
            }
            //画子弹
            for (int i = 0; i < peas.Count; i++)
            {
                if (peas[i] != null)
                    peas[i].Draw(_g);
            }
            //画太阳
            for (int i = 0; i < suns.Count; i++)
            {
                if (suns[i] != null)
                    suns[i].Draw(_g);
            }
            //画最后一波的通知
            if (zombienumber == 21)
            {
                _g.DrawImage(Properties.Resources.最后一波, rectangle6);
                //检查游戏里有没有僵尸存活
                if (zombies.Count == 0)
                {
                    _g.DrawImage(Properties.Resources.WIN, rec);
                    //保证了宇智波鼬的出现
                    k = 2;
                }
                if (k == 2)
                {
                    //弹出messagebox
                    l = 1;
                }
            }
            //僵尸吃掉了你的脑壳
            for (int i = 0; i < zombies.Count; i++)
            {
                if (zombies[i] != null && zombies[i].Rectangle.X <= -100)
                    _g.DrawImage(Properties.Resources.游戏结束, rec);
            }
            //画bitmap
            g.DrawImage(img, new Rectangle(new Point(0, 0), size));
        }

        /// <summary>
        /// 处理鼠标点击事件
        /// </summary>
        /// <param name="point"></param>
        /// <param name="size"></param>
        public void MouseDown(Point point, Size size)
        {
            //坐标吻合
            int newX = point.X * GameWidth / size.Width;
            int newY = point.Y * GameHeight / size.Height;
            Timer.Start();
            //Timer.Stop();
            //坐标吻合
            point = new Point(point.X * GameWidth / size.Width, point.Y * GameHeight / size.Height);
            //处理点击消除阳光
            Sun sunNow = null;
            foreach (var sun in suns)
            {
                //point 这个点在 rec 这个矩形里
                if (sun.Rectangle.Contains(point))
                {
                    //记下来
                    sunNow = sun;
                    //money加上25阳光数
                    Money += 25;
                    break;
                }
            }
            //去除点击到的阳光
            if (sunNow != null)
            {
                suns.Remove(sunNow);
            }
            // 判断植物卡片是否被选中
            var plantSelected = plants.FirstOrDefault(m => m.Rectangle.Contains(point));
            //如果点击到了卡片所在游戏区域
            if (plantSelected != null)
            {
                //判断所点击区域卡片所需要的阳光数
                switch (plantSelected.PlantType)
                {
                    case BlockStatus.豌豆射手:
                        Consume = 100;
                        break;
                    case BlockStatus.向日葵:
                        Consume = 50;
                        break;
                    case BlockStatus.铲子:
                        Consume = 0;
                        break;
                    case BlockStatus.土豆:
                        Consume = 50;
                        break;
                    default:
                        break;
                }
                //判断是否达到该卡片需要的阳光数即点击是否有效
                if (Money - Consume >= 0)
                {
                    Mouseblock = new Plant(plantSelected.Rectangle, plantSelected.PlantType);
                }
            }
            //Timer.Start();
            gameChanged?.Invoke();
        }

        /// <summary>
        /// 处理鼠标拖拽的图片绘画
        /// </summary>
        /// <param name="point"></param>
        /// <param name="size"></param>
        public void MouseMove(Point point, Size size)
        {
            //坐标吻合
            int newX = point.X * GameWidth / size.Width;
            int newY = point.Y * GameHeight / size.Height;
            //Timer.Stop();
            //如果选中了植物卡片
            if (Mouseblock != null)
            {
                //将mouseblock的图片放在鼠标的正中间
                Mouseblock.Rectangle = new Rectangle(new Point(newX - 45, newY - 33), new Size(90, 66));
            }
            //Timer.Start();
        }


        /// <summary>
        /// 处理鼠标松开事件
        /// </summary>
        /// <param name="point"></param>
        /// <param name="size"></param>
        public void MouseUp(Point point, Size size)
        {
            //坐标吻合
            int newX = point.X * GameWidth / size.Width;
            int newY = point.Y * GameHeight / size.Height;
            //Timer.Stop();
            //如果选中了植物卡片
            if (Mouseblock != null)
            {
                //确定被选中的block
                var blockSelected = blocks.FirstOrDefault(m => m.Rectangle.Contains(new Point(newX, newY)));
                //如果被选中的block不为空而且该块没有植物种下而且选中的卡片不为铲子
                if (blockSelected != null && blockSelected.Status == BlockStatus.空白 && Mouseblock.PlantType != BlockStatus.铲子)
                {
                    //种下植物
                    blockSelected.Status = Mouseblock.PlantType;
                    //减钱
                    Money -= Consume;
                    //给格子加血
                    blockSelected.Plantlife += 20;
                    //初始化该植物对应功能的时间
                    switch (blockSelected.Status)
                    {
                        case BlockStatus.豌豆射手:
                            blockSelected.NextGenerateTime = System.DateTime.Now.AddSeconds(2);
                            break;
                        case BlockStatus.向日葵:
                            blockSelected.NextGenerateTime = System.DateTime.Now.AddSeconds(5);
                            break;
                        case BlockStatus.空白:
                            break;
                        case BlockStatus.土豆:
                            blockSelected.Plantlife += 200;
                            break;
                        default:
                            break;
                    }
                }
                //如果被选中的block不为空而且该块有植物种下而且点的是铲子
                if (blockSelected != null && blockSelected.Status != BlockStatus.空白 && Mouseblock.PlantType == BlockStatus.铲子)
                {
                    //单独处理铲子问题
                    blockSelected.Status = BlockStatus.空白;
                    //将铲除的那个块的生命值归零**很重要
                    blockSelected.Plantlife = 1;
                }
                //重置mousedown被点击的卡片
                Mouseblock = null;
            }
            Timer.Start();
        }

        /// <summary>
        /// 处理输赢
        /// </summary>
        /// 
        public int IsGameOver()
        {
            return k;
        }
    }
}
